package timer

import (
	"gitee.com/jiangjiali/leaf/conf"
	"gitee.com/jiangjiali/leaf/log"
	"runtime"
	"time"
)

// Dispatcher one dispatcher per goroutine (goroutine not safe)
type Dispatcher struct {
	ChanTimer chan *Timer
}

func NewDispatcher(l int) *Dispatcher {
	disp := new(Dispatcher)
	disp.ChanTimer = make(chan *Timer, l)
	return disp
}

type Timer struct {
	t  *time.Timer
	cb func()
}

func (t *Timer) Stop() {
	t.t.Stop()
	t.cb = nil
}

func (t *Timer) Cb() {
	defer func() {
		t.cb = nil
		var n any = nil
		if r := recover(); r != n {
			if conf.LenStackBuf > 0 {
				buf := make([]byte, conf.LenStackBuf)
				l := runtime.Stack(buf, false)
				log.Error("%v: %s", r, buf[:l])
			} else {
				log.Error("%v", r)
			}
		}
	}()

	if t.cb != nil {
		t.cb()
	}
}

func (d2 *Dispatcher) AfterFunc(d time.Duration, cb func()) *Timer {
	t := new(Timer)
	t.cb = cb
	t.t = time.AfterFunc(d, func() {
		d2.ChanTimer <- t
	})
	return t
}

type Cron struct {
	t *Timer
}

func (c *Cron) Stop() {
	if c.t != nil {
		c.t.Stop()
	}
}

func (d2 *Dispatcher) CronFunc(cronExpr *CronExpr, _cb func()) *Cron {
	c := new(Cron)

	now := time.Now()
	nextTime := cronExpr.Next(now)
	if nextTime.IsZero() {
		return c
	}

	// callback
	var cb func()
	cb = func() {
		defer _cb()

		now := time.Now()
		nextTime := cronExpr.Next(now)
		if nextTime.IsZero() {
			return
		}
		c.t = d2.AfterFunc(nextTime.Sub(now), cb)
	}

	c.t = d2.AfterFunc(nextTime.Sub(now), cb)
	return c
}

// LoopFunc 由于循环队列只支持cron表达式，而cron表达式最少只有到秒级别，游戏中同步一般都是毫秒级别，所以在此添加毫秒级别的循环队列
func (d2 *Dispatcher) LoopFunc(d time.Duration, _cb func()) *Cron {
	c := new(Cron)

	// callback
	var cb func()
	cb = func() {
		defer _cb()

		c.t = d2.AfterFunc(d, cb)
	}

	c.t = d2.AfterFunc(d, cb)
	return c
}
